﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
using Asol.Reporting.Support.Components;

namespace Asol.Reporting.Editor.Components
{
    #region class PanelOk: nabízí buttony: Použít, Uložit, Zavřít
    /// <summary>
    /// PanelOk: nabízí buttony: Použít, Uložit, Zavřít
    /// </summary>
    [DefaultEvent("Save")]
    public class PanelOk : Panel
    {
        #region Konstrukce, layout
        /// <summary>
        /// Konstruktor
        /// </summary>
        public PanelOk()
        {
            this.Initialize();
        }
        private void Initialize()
        {
            this.Height = 35;
            this.Dock = DockStyle.Bottom;
            this._ButtonApply = CreateButton("Použít", Pics.IconLibrary16.DialogApply_FromFile, 0, this.Apply_Click);
            this.Controls.Add(this._ButtonApply);
            this._ButtonSave = CreateButton("Uložit", Pics.IconLibrary16.DialogSave_FromFile, 1, this.Save_Click);
            this.Controls.Add(this._ButtonSave);
            this._ButtonCancel = CreateButton("Zavřít", Pics.IconLibrary16.DialogCancel_FromFile, 2, this.Cancel_Click);
            this.Controls.Add(this._ButtonCancel);

            this.ButtonsAlignment = ContentAlignment.BottomRight;
            this.Buttons = PanelOkButtons.ApplySaveCancel;
            this.DirtySensitive = false;

            this.ParentChanged += new EventHandler(PanelOk_ParentChanged);
        }

        void PanelOk_ParentChanged(object sender, EventArgs e)
        {
            if (this.Parent == null) return;
            Form form = this.FindForm();
            if (form == null) return;
            form.CancelButton = this._ButtonCancel;
        }
        private DButton CreateButton(string text, Image image, int tabIndex, EventHandler click)
        {
            DButton button = new DButton();
            button.Text = text;
            button.Image = image;
            button.TabIndex = tabIndex;
            button.Click += click;
            return button;
        }
        #endregion
        #region Layout
        private void _SetLayout()
        {
            if (this._ButtonCancel == null) return;
            
            Size cs = this.ClientSize;
            if (cs.Height <= cs.Width * 3 / 5)
                _SetLayoutH();
            else
                _SetLayoutV();
        }
        private void _SetLayoutH()
        {
            int visApply = _VisibleApply;
            int visSave = _VisibleSave;
            int visCancel = _VisibleCancel;
            int buttonCnt = visApply + visSave + visCancel;
            if (buttonCnt > 0)
            {
                Size clientSize = this.ClientSize;
                int top = 3;
                int height = clientSize.Height - 6;
                int buttonWidth = 120;
                int spacing = 6;
                int innerWidth = clientSize.Width - 2 * spacing;
                int buttonsWidth = buttonCnt * buttonWidth + (buttonCnt - 1) * spacing;
                if (buttonsWidth > innerWidth)
                    buttonWidth = (innerWidth - ((buttonCnt - 1) * spacing)) / buttonCnt;
                int left = _SetLayoutHGetFirst(spacing, innerWidth - buttonCnt * buttonWidth - (buttonCnt - 1) * spacing);
                
                this._SetLayoutH(this._ButtonApply, visApply, ref left, buttonWidth, top, height, spacing);
                this._SetLayoutH(this._ButtonSave, visSave, ref left, buttonWidth, top, height, spacing);
                this._SetLayoutH(this._ButtonCancel, visCancel, ref left, buttonWidth, top, height, spacing);
            }
            this._ButtonApply.Visible = (_VisibleApply == 1);
            this._ButtonSave.Visible = (_VisibleSave == 1);
            this._ButtonCancel.Visible = (_VisibleCancel == 1);
        }
        private int _SetLayoutHGetFirst(int spacing, int freeSpace)
        {
            switch (this.ButtonsAlignment)
            {
                case ContentAlignment.TopLeft:
                case ContentAlignment.MiddleLeft:
                case ContentAlignment.BottomLeft:
                    return spacing;
                case ContentAlignment.TopCenter:
                case ContentAlignment.MiddleCenter:
                case ContentAlignment.BottomCenter:
                    return spacing + (freeSpace / 2);
                case ContentAlignment.TopRight:
                case ContentAlignment.MiddleRight:
                case ContentAlignment.BottomRight:
                    return spacing + freeSpace;
            }
            return spacing + (freeSpace / 2);
        }
        private void _SetLayoutH(DButton button, int visible, ref int left, int width, int top, int height, int spacing)
        {
            if (visible == 1)
            {
                button.Bounds = new Rectangle(left, top, width, height);
                left += (width + spacing);
            }
        }
        private void _SetLayoutV()
        {
            int visApply = _VisibleApply;
            int visSave = _VisibleSave;
            int visCancel = _VisibleCancel;
            int buttonCnt = visApply + visSave + visCancel;
            if (buttonCnt > 0)
            {
                Size clientSize = this.ClientSize;
                int left = 3;
                int width = clientSize.Width - 6;
                int buttonHeight = 29;
                int spacing = 3;
                int innerHeight = clientSize.Height - 2 * spacing;
                int buttonsHeight = buttonCnt * buttonHeight + (buttonCnt - 1) * spacing;
                if (buttonsHeight > innerHeight)
                    buttonHeight = (innerHeight - ((buttonCnt - 1) * spacing)) / buttonCnt;
                int top = _SetLayoutVGetFirst(spacing, innerHeight - buttonCnt * buttonHeight - (buttonCnt - 1) * spacing);

                this._SetLayoutV(this._ButtonApply, visApply, ref top, buttonHeight, left, width, spacing);
                this._SetLayoutV(this._ButtonSave, visSave, ref top, buttonHeight, left, width, spacing);
                this._SetLayoutV(this._ButtonCancel, visCancel, ref top, buttonHeight, left, width, spacing);
            }
            this._ButtonApply.Visible = (_VisibleApply == 1);
            this._ButtonSave.Visible = (_VisibleSave == 1);
            this._ButtonCancel.Visible = (_VisibleCancel == 1);
        }
        private int _SetLayoutVGetFirst(int spacing, int freeSpace)
        {
            switch (this.ButtonsAlignment)
            {
                case ContentAlignment.TopLeft:
                case ContentAlignment.TopCenter:
                case ContentAlignment.TopRight:
                    return spacing;
                case ContentAlignment.MiddleLeft:
                case ContentAlignment.MiddleCenter:
                case ContentAlignment.MiddleRight:
                    return spacing + (freeSpace / 2);
                case ContentAlignment.BottomLeft:
                case ContentAlignment.BottomCenter:
                case ContentAlignment.BottomRight:
                    return spacing + freeSpace;
            }
            return spacing + (freeSpace / 2);
        }
        private void _SetLayoutV(DButton button, int visible, ref int top, int height, int left, int width, int spacing)
        {
            if (visible == 1)
            {
                button.Bounds = new Rectangle(left, top, width, height);
                top += (height + spacing);
            }
        }
        private void _SetEnabled()
        {
            bool saveEnabled = (!this.DirtySensitive || this.IsDirty);
            this._ButtonApply.Enabled = saveEnabled;
            this._ButtonSave.Enabled = saveEnabled;
        }
        private int _VisibleApply { get { return this.IsVisibleButton(PanelOkButtons.ApplyCancel, PanelOkButtons.ApplySaveCancel); } }
        private int _VisibleSave { get { return this.IsVisibleButton(PanelOkButtons.SaveCancel, PanelOkButtons.ApplySaveCancel); } }
        private int _VisibleCancel { get { return this.IsVisibleButton(PanelOkButtons.Cancel, PanelOkButtons.ApplyCancel, PanelOkButtons.SaveCancel, PanelOkButtons.ApplySaveCancel); } }
        private int IsVisibleButton(params PanelOkButtons[] buttons)
        {
            foreach (PanelOkButtons button in buttons)
            {
                if (this._Buttons == button) return 1;
            }
            return 0;
        }
        private DButton _ButtonApply;
        private DButton _ButtonSave;
        private DButton _ButtonCancel;
        #endregion
        #region Eventy buttonů
        void Apply_Click(object sender, EventArgs e)
        {
            this.OnSave();
        }
        void Save_Click(object sender, EventArgs e)
        {
            this.OnSave();
            this.OnClose();
        }
        void Cancel_Click(object sender, EventArgs e)
        {
            this.OnClose();
        }
        private void OnSave()
        {
            if (this.Save != null)
                this.Save(this, EventArgs.Empty);
        }
        private void OnClose()
        {
            Form form = this.FindForm();
            if (form != null)
                form.Close();
        }
        /// <summary>
        /// Při změně velikosti
        /// </summary>
        /// <param name="e"></param>
        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            this._SetLayout();
        }
        #endregion
        #region Public property a eventy
        /// <summary>
        /// Zobrazené buttony
        /// </summary>
        [Browsable(true)]
        [Category("PanelOk")]
        [Description("Určuje zobrazené buttony")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public PanelOkButtons Buttons
        {
            get { return this._Buttons; }
            set { this._Buttons = value; this._SetLayout(); }
        }
        private PanelOkButtons _Buttons;
        /// <summary>
        /// Zarovnání buttonů v panelu
        /// </summary>
        [Browsable(true)]
        [Category("PanelOk")]
        [Description("Zarovnání buttonů v panelu")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public ContentAlignment ButtonsAlignment
        {
            get { return this._ButtonsAlignment; }
            set { this._ButtonsAlignment = value; this._SetLayout(); }
        }
        private ContentAlignment _ButtonsAlignment;
        /// <summary>
        /// Příznak, zda data jsou Dirty (změněná).
        /// Pokud je true, pak buttony Apply a Save reagují (jsou Enabled), jinak jsou Disabled.
        /// Pro tuto reakci musí být nastaveno DirtySensitive = true.
        /// </summary>
        [Browsable(true)]
        [Category("PanelOk")]
        [Description("Příznak, zda data jsou Dirty (změněná)")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public bool IsDirty
        {
            get { return this._IsDirty; }
            set { this._IsDirty = value; this._SetEnabled(); }
        }
        private bool _IsDirty;
        /// <summary>
        /// Citlivost buttonů Apply a Save na stav IsDirty.
        /// </summary>
        [Browsable(true)]
        [Category("PanelOk")]
        [Description("Citlivost buttonů Apply a Save na stav IsDirty")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public bool DirtySensitive
        {
            get { return this._DirtySensitive; }
            set { this._DirtySensitive = value; this._SetEnabled(); }
        }
        private bool _DirtySensitive;
        /// <summary>
        /// Událost, kdy uživatel na panelu zvolil Použít nebo Uložit.
        /// </summary>
        [Browsable(true)]
        [Category("PanelOk")]
        [Description("Událost, kdy uživatel na panelu zvolil Použít nebo Uložit")]
        public event EventHandler Save;
        #endregion
    }
    #endregion
    #region enum PanelOkButtons
    /// <summary>
    /// Kombinace buttonů
    /// </summary>
    public enum PanelOkButtons
    {
        None,
        Cancel,
        ApplyCancel,
        SaveCancel,
        ApplySaveCancel
    }
    #endregion
}
